/*
* 创建和关联两个渲染缓存
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "../common/LoadShaders.h"
#include "../include/vmath.h"

#define BUFFER_OFFSET(offset) ((void*) (offset))

const unsigned int SCR_WIDTH = 512;
const unsigned int SCR_HEIGHT = 512;

void processInput(GLFWwindow *window)
{
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
    {
        //将窗口设置为关闭，跳出循环
        glfwSetWindowShouldClose(window, 1);
    }
}

void framebuffer_size_callback(GLFWwindow* window, int width, int height);

enum VAO_IDs { Triangles, NumVAOs };
enum Buffer_IDs { ArrayBuffer, NumBuffers };
enum Attrib_IDs { vPosition = 0, vColor=1 };

//GLuint VAOs[NumVAOs];
//GLuint Buffers[NumBuffers];

GLuint ebo[1];
GLuint vao[1];
GLuint vbo[1];

GLuint position_buffer;
GLuint color_buffer;
GLuint model_matrix_buffer;
GLuint color_tbo;
GLuint model_matrix_tbo;

const GLuint NumVertices = 3;
GLint render_view_matrix_loc;
GLint render_projection_matrix_loc;
float aspect = 1.0;

int position_loc;
int color_loc;

struct VectexData {
    unsigned char color[4];
    float position[4];
};

enum { Color, Depth, NumRenderbuffers };
unsigned framebuffer, renderbuffer[NumRenderbuffers];

const VectexData vertices[NumVertices] = {
    {{255,   0,   0, 255}, {-0.90, -0.90,  1.0 }}, //triangle 1
    {{  0, 255,   0, 255}, {  0.5, -0.45, -1.0 }},
    {{  0,   0, 255, 255}, {-0.90,  0.85,  1.0 }},

};
GLuint program;
int defaultFrameBuffer;

void CheckError(int line)
{
    unsigned int error = glGetError();
    if(error != GL_NO_ERROR){
        std::cout << line << ":" << "0x0" << hex << error << std::endl;
        exit(-1);
    }
}
void init(void)
{
    glClearColor(1, 1, 1, 1);

    ShaderInfo shaders[] = {
        { GL_VERTEX_SHADER, "triangles.vert" },
        { GL_FRAGMENT_SHADER, "triangles.frag" },
        { GL_NONE, NULL }
    };

    program = LoadShaders(shaders);
    glUseProgram(program);

    render_view_matrix_loc = glGetUniformLocation(program, "view_matrix");
    render_projection_matrix_loc = glGetUniformLocation(program, "projection_matrix");

    position_loc = glGetAttribLocation(program, "vPos");
    color_loc = glGetAttribLocation(program, "vColor");


    glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFrameBuffer);


// not work
//    glGenRenderbuffers(NumRenderbuffers, renderbuffer);
//    glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer[Color]);
//    glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, SCR_WIDTH, SCR_HEIGHT); // 渲染缓存-颜色


//    glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer[Depth]); // 渲染缓存-深度
//    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT32, SCR_WIDTH, SCR_HEIGHT);



    glGenFramebuffers(1, &framebuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);


    // 生成纹理
    unsigned int texColorBuffer;
    glGenTextures(1, &texColorBuffer);
    glBindTexture(GL_TEXTURE_2D, texColorBuffer);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, SCR_WIDTH, SCR_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glBindTexture(GL_TEXTURE_2D, 0);

    // 将它附加到当前绑定的帧缓冲对象
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texColorBuffer, 0);

    unsigned int rbo;
    glGenRenderbuffers(1, &rbo);
    glBindRenderbuffer(GL_RENDERBUFFER, rbo);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, SCR_WIDTH, SCR_HEIGHT);
    glBindRenderbuffer(GL_RENDERBUFFER, 0);

    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
                              GL_RENDERBUFFER, rbo); // 渲染缓存关联到帧缓存

    // 最后，我们希望检查帧缓冲是否是完整的，如果不是，我们将打印错误信息。
    if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
        std::cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << std::endl;
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    glEnable(GL_DEPTH_TEST);

    // set vertex property
    glGenVertexArrays(1, vao);
    glBindVertexArray(vao[0]);

    glGenBuffers(1, vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
    glBufferData(GL_ARRAY_BUFFER,
                 sizeof(vertices),
                 vertices,
                 GL_STATIC_DRAW);   

    glVertexAttribPointer(color_loc, 4, GL_UNSIGNED_BYTE,
                          GL_TRUE,
                          sizeof(VectexData),
                          BUFFER_OFFSET(0));

    glVertexAttribPointer(position_loc, 2, GL_FLOAT,
                          GL_FALSE,
                          sizeof(VectexData),
                          BUFFER_OFFSET(sizeof(vertices[0].color)));



    glEnableVertexAttribArray(position_loc);
    glEnableVertexAttribArray(color_loc);

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

}

void display(void)
{
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer);

    glViewport(0, 0, SCR_WIDTH, SCR_HEIGHT);
    glClearColor(1, 1, 1, 1);
    // 渲染到渲染缓存
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

//    GLenum fboBuffers[]={
//        GL_COLOR_ATTACHMENT0,
//    };
//    glDrawBuffers(1,fboBuffers); // 缓冲区映射

    glUseProgram(program);
    glBindVertexArray(vao[0]);
    glDrawArrays(GL_TRIANGLES, 0, 3);

    // 从渲染缓存读取，绘制到窗口系统的帧缓存中

    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, defaultFrameBuffer);
    glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);


    glViewport(0, 0, SCR_WIDTH, SCR_HEIGHT);
    glClearColor(0, 0, 0, 1);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

//     执行拷贝操作
//    glReadBuffer(GL_COLOR_ATTACHMENT0);
    glBlitFramebuffer(0, 0, SCR_WIDTH, SCR_HEIGHT, 0, 0, SCR_WIDTH, SCR_HEIGHT,
                      GL_COLOR_BUFFER_BIT, GL_LINEAR);

    glBlitFramebuffer(0, 0, SCR_WIDTH, SCR_HEIGHT, SCR_WIDTH-56, SCR_HEIGHT-56, SCR_WIDTH, SCR_HEIGHT,
                      GL_COLOR_BUFFER_BIT, GL_LINEAR);

    glFlush();
}


int main()
{
    //glfw初始化
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    //glfw创建窗口
    GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "OpenGL编程指南", NULL, NULL);

    if (window == NULL)
    {
        printf("创建窗口失败");
        //终止
        glfwTerminate();
        return -1;
    }

    //显示窗口
    glfwMakeContextCurrent(window);

    //设置回调，当窗口大小调整后将调用该回调函数
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

    // glad初始化
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        printf("加载失败");
        return -1;
    }

    init();

    // 使用循环达到循环渲染效果
    while (!glfwWindowShouldClose(window))
    {
        display();
        //自定义输入事件
        processInput(window);
        //交互缓冲区，否则显示空白
        glfwSwapBuffers(window);
        //输入输出事件,否则无法对窗口进行交互
        glfwPollEvents();
    }

    //终止渲染 关闭并清理glfw本地资源
    glfwTerminate();
    return 0;
}


void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
    glViewport(0, 0, width, height);
    display();
}
